
function TerrainManager(width, height, fallingDiv) {
	this.width = width;
	this.height = height;
	this.blockMap;
	this.fallingDiv = fallingDiv;
	this.fallingTerrain = [];
	this.wordBlocks = [];

	var WORD_TAGS = set("a", "b", "big", "body", "cite", "code", "dd", "div", "dt", "em", "font", "h1", "h2", "h3", "h4", "h5", "h6",
			"i", "label", "legend", "li", "p", "pre", "small", "span", "strong", "sub", "sup", "td", "th", "tt", "img");
//	var OTHER_TAGS = set("button", "canvas", "iframe", "img", "input", "select", "textarea");
	var OTHER_TAGS = set("img", "input", "select", "textarea");

	this.init = function() {
		var textElements = [];
		var otherElements = [];
		this.blockMap = new Map2D(this.width, this.height, 40, 40);

		this.domNodes = document.getElementsByTagName("*");
		for (i = 0, this.domNodes.length; i < this.domNodes.length; i++) {
			el = this.domNodes[i];
			
			var visible = window.getComputedStyle(el).visibility;
			if (visible.trim().toLowerCase() == 'hidden') {
				console.log(el);
				continue;
			}
			
			if (el && el.tagName.toLowerCase() in OTHER_TAGS) {
				otherElements.push(el);
			}
			for ( var j = 0; j < el.childNodes.length; j++) {
				textEl = el.childNodes[j];
				if (textEl && textEl.nodeType === Node.TEXT_NODE && textEl.nodeValue.trim().length > 0 && el.tagName.toLowerCase() in WORD_TAGS
						&& el.processed != true) {
					textElements.push(el);
				}
			}
		}
		for (i = 0; i < textElements.length; i++) {
			el = textElements[i];
			this.blockToWords(el);
			el.processed = true;
		}
		
		for (i = 0; i < this.wordBlocks.length; i++) {
			this.addElement(this.wordBlocks[i], Terrain.STATUS_WORD);
		}
		
		for (i = 0; i < otherElements.length; i++) {
			this.addElement(otherElements[i], Terrain.STATUS_CHAR);
		}
	};

	this.breakDownMore = function(terrain) {
		if (terrain.status == Terrain.STATUS_WORD) {
			this.blockMap.remove(terrain);
			this.wordToChars(terrain.element);
		}
	};

	this.getTerrain = function(x, y, width, height) {
	  var subGrid = this.blockMap.get(x, y, width, height);
    res = [];
    for ( var i = 0; i < subGrid.length; ++i) {
      var nearby_blocks = subGrid[i];
      for (var j = 0; j < nearby_blocks.length; ++j) {
        var currentBlock = nearby_blocks[j];
        if (overlaps(x, y, width, height, currentBlock.x, currentBlock.y, currentBlock.width, currentBlock.height)) {
          var found = false;
          for (var k = 0; k < res.length; k++) {
            if (res[k] === currentBlock) {
              found = true;
              break;
            }
          }
          if (!found) {
            res.push(currentBlock);
          }
        }
      }
    }
	  return res;
	};

	this.destroyTerrain = function(terrain) {
		if (terrain.destroyed || terrain.indestructible)
			return;
		this.fallingTerrain.push(new FallingTerrain(terrain, this.fallingDiv));
		terrain.destroy();
		this.blockMap.remove(terrain);
	};

	this.wordToChars = function(word) {
		var element = word.cloneNode(true);
		pos = $(word).offset();
		$(element).offset(pos);
		element.style.position = 'absolute';
		element.style.color = $(word).css('color');
		element.style.textDecoration = $(word).css('text-decoration');
		element.style.fontSize = $(word).css('font-size');
		element.style.fontWeight = $(word).css('font-weight');
		element.style.fontStyle = $(word).css('font-style');
		
		this.fallingDiv.appendChild(element);
		word.style.visibility = 'hidden';
		word = element;
		
		textEl = word.firstChild;
		chars = textEl.nodeValue.split("");
		added = [];
		for ( var i = 0; i < chars.length; i++) {
			n = document.createElement("span")
			n.innerHTML = chars[i]
			word.insertBefore(n, textEl)

			if (chars[i].trim() != "")
				added.push(n);
		}
		word.removeChild(textEl);
		
		for ( var i = 0; i < added.length; i++) {
			this.addElement(added[i], Terrain.STATUS_CHAR);
		}
		
		
	};

	this.blockToWords = function(block) {
		for ( var j = 0; j < block.childNodes.length; j++) {
			textEl = block.childNodes[j];
			if (!textEl || textEl.nodeType !== Node.TEXT_NODE || textEl.nodeValue.trim().length <= 0)
				continue;
			words = textEl.nodeValue.split(/\s+/);
			ws = textEl.nodeValue.split(/\S+/);
			len = Math.max(words.length, ws.length);

			if (ws.length > 0 && ws[0].length === 0) {
				ws.shift();
			}
			for ( var i = 0; i < len; i++) {
				if (i < words.length && words[i].length > 0) {
					var hyphenated = words[i].split("-");
					for (var j = 0; j < hyphenated.length; j++) {
						n = document.createElement("span");
						n.innerHTML = hyphenated[j];
						block.insertBefore(n, textEl);
						this.wordBlocks.push(n);
						if (j + 1 < hyphenated.length) {
							n = document.createElement("span");
							n.innerHTML = "-";
							block.insertBefore(n, textEl);
							this.wordBlocks.push(n);
						}
					}

				}
				if (i < ws.length && ws[i].length > 0) {
					n = document.createTextNode(ws[i])
					block.insertBefore(n, textEl)
				}
			}
			block.removeChild(textEl);
		}
	};
	
	this.addTerrain = function(terrain) {
		this.blockMap.add(terrain, terrain.x, terrain.y, terrain.width, terrain.height);
	};
	
	this.removeTerrain = function(terrain) {
		this.blockMap.remove(terrain);
	};
	
	this.addElement = function(el, status) {
		el.terrain = true;
		off = jQuery(el).offset();
		var elementWidth = jQuery(el).outerWidth() ;
		var elementHeight = jQuery(el).outerHeight();
		var elementX = off.left;
		var elementY = off.top;
		
		var width = jQuery(el).width();
		var height = jQuery(el).height();
		var x = off.left + parseInt(jQuery(el).css("padding-left").replace("px", ""));
		var y = off.top + parseInt(jQuery(el).css("padding-top").replace("px", ""));
		
		if (width != 0 && height != 0) {
			// console.log("New terrain at " + [x, y] + " sized " + [w, h]);
			if (status == Terrain.STATUS_WORD || (status == Terrain.STATUS_CHAR && width < 25 && height < 25)) {
				el.dcChildCount = 1;
				width -= 1;
				height -= 7;
				x += 1;
				y += 5;
				var terrain = new Terrain(x, y, width, height, el, elementX, elementY, elementWidth, elementHeight, false, status, false, true);
				this.blockMap.add(terrain, terrain.x, terrain.y, terrain.width, terrain.height);
			}
			else {
				el.dcChildCount = Math.ceil(width / 10) * Math.ceil(height / 10);
				for (var currentX = 0; currentX < width; currentX += 10) {
					for (var currentY = 0; currentY < height; currentY += 10) {
						var terrain = new Terrain(currentX + x, currentY + y, Math.min(10, width - currentX), Math.min(10, height - currentY), el, elementX, elementY, elementWidth, elementHeight, true, status, false, true);
						this.blockMap.add(terrain, terrain.x, terrain.y, terrain.width, terrain.height);
					}
				}
			}
//			var terrain = new Terrain(x, y, w, h, el);
//			terrain.status = status;
//			this.blockMap.add(terrain, terrain.x, terrain.y, terrain.width, terrain.height);
		}
	};

	this.step = function() {
		var last = this.fallingTerrain.length - 1;
		for ( var i = 0; i < last + 1; i++) {
			this.fallingTerrain[i].step();
			if (this.fallingTerrain[i].outsideOf(0, 0, this.width, this.height)) {
				this.fallingTerrain[i].destroy();
				this.fallingTerrain[i] = this.fallingTerrain[last];
				last--;
				i--;
				this.fallingTerrain.pop();
			}
		}
	};

	this.draw = function(ctx) {
		this.blockMap.draw(ctx);
	};
	this.init();
}